home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
ms_sh21s.zip
/
SH210
/
SRC
/
SH11.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-14
|
21KB
|
949 lines
/*
* MS-DOS SHELL - Maths Evaluation Functions
*
* MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited and Paul Falstad
*
* This code is based on (in part) the shell program written by Paul Falstad
* and is subject to the following copyright restrictions:
*
* 1. Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in the
* source form and the copyright notice in file sh6.c is displayed
* on entry to the program.
*
* 2. The sources (or parts thereof) or objects generated from the sources
* (or parts of sources) cannot be sold under any circumstances.
*
* This source is based on the math.c (mathematical expression evaluation) from
* the Z shell. Z Shell is free software, under the GNU license. This
* code is included in this program under the provisions of paragraph 8 of
* GNU GENERAL PUBLIC LICENSE, Version 1, February 1989. I contacted Paul
* via E-Mail, and he is happy to allow the source to be included in this
* program.
*
* $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh11.c,v 2.2 1992/11/06 10:03:44 istewart Exp $
*
* $Log: sh11.c,v $
* Revision 2.2 1992/11/06 10:03:44 istewart
* 214 Beta test updates
*
* Revision 2.2 1992/11/06 10:03:44 istewart
* 214 Beta test updates
*
* Revision 2.1 1992/07/10 10:52:48 istewart
* 211 Beta updates
*
* Revision 2.0 1992/04/13 17:39:09 Ian_Stewartson
* MS-Shell 2.0 Baseline release
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#ifdef OS2
#define INCL_DOSSESMGR
#include <os2.h>
#else
#include <dos.h>
#endif
#include "sh.h"
#define STACK_SIZE 100 /* Stack size */
#define MAX_PRECEDENCE 15
#define MAX_VARIABLES 32 /* Number of user variables */
/*
* Some macros
*/
#define POP_2_VALUES() b = stack[StackPointer--].val; \
a = stack[StackPointer--].val;
#define PUSH_VALUE_ON_STACK(X) PushOnToStack ((long)(X), -1);
#define SET_VALUE_ON_STACK(X) PushOnToStack (SetVariableValue \
(lv, (long)(X)), lv);
/* the value stack */
static int LastToken; /* Last token */
static int StackPointer = -1; /* Stack pointer */
static struct MathsStack {
int lval;
long val;
} stack[STACK_SIZE];
static int NumberOfVariables = 0; /* Number of variables */
static char *ListOfVariableNames[MAX_VARIABLES];
static char *CStringp; /* Current position */
static long yyval;
static int yylval;
static int JustParsing = 0; /* Nonzero means we are */
/* not evaluating, just */
/* parsing */
static bool RecogniseUnaryOperator = TRUE; /* TRUE means recognize */
/* unary plus, minus, */
/* etc. */
/*
* LEFT_RIGHT_A = left-to-right associativity
* RIGHT_LEFT_A = right-to-left associativity
* BOOL_A = short-circuiting boolean
*/
#define LEFT_RIGHT_A 0
#define RIGHT_LEFT_A 1
#define BOOL_A 2
#define OP_OPEN_PAR 0
#define OP_CLOSE_PAR 1
#define OP_NOT 2
#define OP_COMPLEMENT 3
#define OP_POST_PLUS 4
#define OP_POST_MINUS 5
#define OP_UNARY_PLUS 6
#define OP_UNARY_MINUS 7
#define OP_BINARY_AND_EQUALS 8
#define OP_BINARY_XOR_EQUALS 9
#define OP_BINARY_OR_EQUALS 10
#define OP_MULTIPLY 11
#define OP_DIVIDE 12
#define OP_MODULUS 13
#define OP_PLUS 14
#define OP_MINUS 15
#define OP_SHIFT_LEFT 16
#define OP_SHIFT_RIGHT 17
#define OP_LESS 18
#define OP_LESS_EQUALS 19
#define OP_GREATER 20
#define OP_GREATER_EQUALS 21
#define OP_EQUALS 22
#define OP_NOT_EQUALS 23
#define OP_LOGICAL_AND_EQUALS 24
#define OP_LOGICAL_OR_EQUALS 25
#define OP_LOGICAL_XOR_EQUALS 26
#define OP_QUESTION_MARK 27
#define OP_COLON 28
#define OP_SET 29
#define OP_PLUS_EQUAL 30
#define OP_MINUS_EQUAL 31
#define OP_MULTIPLY_EQUAL 32
#define OP_DIVIDE_EQUAL 33
#define OP_MODULUS_EQUAL 34
#define OP_BINARY_AND_SET 35
#define OP_BINARY_XOR_SET 36
#define OP_BINARY_OR_SET 37
#define OP_SHIFT_LEFT_EQUAL 38
#define OP_SHIFT_RIGHT_EQUAL 39
#define OP_LOGICAL_AND_SET 40
#define OP_LOGICAL_OR_SET 41
#define OP_LOGICAL_XOR_SET 42
#define OP_COMMA 43
#define OP_END_OF_INPUT 44
#define OP_PRE_PLUS 45
#define OP_PRE_MINUS 46
#define OP_NUMERIC_VALUE 47
#define OP_VARIABLE 48
#define MAX_OPERATORS 49
/* precedences */
static struct Operators {
int Precedences; /* Operator Precedences */
int Type; /* Operator Association */
} Operators [MAX_OPERATORS] = {
{ 1, LEFT_RIGHT_A }, /* 0 - ( */
{ 137, LEFT_RIGHT_A }, /* 1 - ) */
{ 2, RIGHT_LEFT_A }, /* 2 - ! */
{ 2, RIGHT_LEFT_A }, /* 3 - ~ */
{ 2, RIGHT_LEFT_A }, /* 4 - x++ */
{ 2, RIGHT_LEFT_A }, /* 5 - x-- */
{ 2, RIGHT_LEFT_A }, /* 6 - + */
{ 2, RIGHT_LEFT_A }, /* 7 - - */
{ 4, LEFT_RIGHT_A }, /* 8 - & */
{ 5, LEFT_RIGHT_A }, /* 9 - ^ */
{ 6, LEFT_RIGHT_A }, /* 10 - | */
{ 7, LEFT_RIGHT_A }, /* 11 - * */
{ 7, LEFT_RIGHT_A }, /* 12 - / */
{ 7, LEFT_RIGHT_A }, /* 13 - % */
{ 8, LEFT_RIGHT_A }, /* 14 - + */
{ 8, LEFT_RIGHT_A }, /* 15 - - */
{ 3, LEFT_RIGHT_A }, /* 16 - < */
{ 3, LEFT_RIGHT_A }, /* 17 - > */
{ 9, LEFT_RIGHT_A }, /* 18 - < (less than) */
{ 9, LEFT_RIGHT_A }, /* 19 - <= (less than equal) */
{ 9, LEFT_RIGHT_A }, /* 20 - > (greater than) */
{ 9, LEFT_RIGHT_A }, /* 21 - >= (greater than equal) */
{ 10, LEFT_RIGHT_A }, /* 22 - == */
{ 10, LEFT_RIGHT_A }, /* 23 - != */
{ 11, BOOL_A }, /* 24 - && */
{ 12, BOOL_A }, /* 25 - || */
{ 12, LEFT_RIGHT_A }, /* 26 - ^^ */
{ 13, RIGHT_LEFT_A }, /* 27 - ? */
{ 13, RIGHT_LEFT_A }, /* 28 - : */
{ 14, RIGHT_LEFT_A }, /* 29 - = */
{ 14, RIGHT_LEFT_A }, /* 30 - += */
{ 14, RIGHT_LEFT_A }, /* 31 - -= */
{ 14, RIGHT_LEFT_A }, /* 32 - *= */
{ 14, RIGHT_LEFT_A }, /* 33 - /= */
{ 14, RIGHT_LEFT_A }, /* 34 - %= */
{ 14, RIGHT_LEFT_A }, /* 35 - &= */
{ 14, RIGHT_LEFT_A }, /* 36 - ^= */
{ 14, RIGHT_LEFT_A }, /* 37 - |= */
{ 14, RIGHT_LEFT_A }, /* 38 - <= */
{ 14, RIGHT_LEFT_A }, /* 39 - >= */
{ 14, BOOL_A }, /* 40 - &&= */
{ 14, BOOL_A }, /* 41 - ||= */
{ 14, RIGHT_LEFT_A }, /* 42 - ^^= */
{ 15, RIGHT_LEFT_A }, /* 43 - , */
{ 200, RIGHT_LEFT_A }, /* 44 - End of input */
{ 2, RIGHT_LEFT_A }, /* 45 - ++x */
{ 2, RIGHT_LEFT_A }, /* 46 - --x */
{ 0, LEFT_RIGHT_A }, /* 47 - Numeric value */
{ 0, LEFT_RIGHT_A } /* 48 - Variable */
};
/*
* Functions
*/
static void near PushOnToStack (long, int);
static long near SetVariableValue (int, long);
static bool near CheckNotZero (long);
static void near ProcessOperator (int);
static void near ProcessBinaryOperator (int);
static void near ParseMathsExpression (int);
static int near MathsLexicalAnalyser (void);
static int near DecideSingleOperator (int, int);
static int near DecideDoubleOperator (char, int, int, int, int);
static int near DecideSignOperator (char, int, int, int, int, int);
/*
* Analyse the string
*/
static int near MathsLexicalAnalyser (void)
{
while (TRUE)
{
switch (*(CStringp++))
{
case '+':
return DecideSignOperator ('+', OP_PRE_PLUS,
OP_POST_PLUS,
OP_PLUS_EQUAL,
OP_UNARY_PLUS,
OP_PLUS);
case '-':
return DecideSignOperator ('+', OP_PRE_MINUS,
OP_POST_MINUS,
OP_MINUS_EQUAL,
OP_UNARY_MINUS,
OP_MINUS);
case CHAR_OPEN_PARATHENSIS:
RecogniseUnaryOperator = TRUE;
return OP_OPEN_PAR;
case CHAR_CLOSE_PARATHENSIS:
return OP_CLOSE_PAR;
case '!':
if (*CStringp == '=')
{
RecogniseUnaryOperator = TRUE;
CStringp++;
return OP_NOT_EQUALS;
}
return OP_NOT;
case '~':
return OP_COMPLEMENT;
case '&':
return DecideDoubleOperator ('&', OP_LOGICAL_AND_SET,
OP_BINARY_AND_SET,
OP_LOGICAL_AND_EQUALS,
OP_BINARY_AND_EQUALS);
case '|':
return DecideDoubleOperator ('|', OP_LOGICAL_OR_SET,
OP_BINARY_OR_SET,
OP_LOGICAL_OR_EQUALS,
OP_BINARY_OR_EQUALS);
case CHAR_XOR:
return DecideDoubleOperator (CHAR_XOR, OP_LOGICAL_XOR_SET,
OP_BINARY_XOR_SET,
OP_LOGICAL_XOR_EQUALS,
OP_BINARY_XOR_EQUALS);
case '*':
return DecideSingleOperator (OP_MULTIPLY_EQUAL, OP_MULTIPLY);
case '/':
return DecideSingleOperator (OP_DIVIDE_EQUAL, OP_DIVIDE);
case '%':
return DecideSingleOperator (OP_MODULUS_EQUAL, OP_MODULUS);
case '<':
return DecideDoubleOperator ('<', OP_SHIFT_LEFT_EQUAL,
OP_LESS_EQUALS,
OP_SHIFT_LEFT,
OP_LESS);
case '>':
return DecideDoubleOperator ('>', OP_SHIFT_RIGHT_EQUAL,
OP_GREATER_EQUALS,
OP_SHIFT_RIGHT,
OP_GREATER);
case '=':
return DecideSingleOperator (OP_EQUALS, OP_SET);
case '?':
RecogniseUnaryOperator = TRUE;
return OP_QUESTION_MARK;
case ':':
RecogniseUnaryOperator = TRUE;
return OP_COLON;
case ',':
RecogniseUnaryOperator = TRUE;
return OP_COMMA;
case '\0':
RecogniseUnaryOperator = TRUE;
CStringp--;
return OP_END_OF_INPUT;
case CHAR_OPEN_BRACKETS:
RecogniseUnaryOperator = FALSE;
LastNumberBase = (int)strtol (CStringp, &CStringp, 10);
if (*CStringp == CHAR_CLOSE_BRACKETS)
CStringp++;
yyval = strtol (CStringp, &CStringp, LastNumberBase);
return OP_NUMERIC_VALUE;
default:
if (isspace (*(CStringp - 1)))
break;
/* Check for a numeric value */
if (isdigit (*--CStringp))
{
RecogniseUnaryOperator = FALSE;
yyval = strtol (CStringp, &CStringp, 10);
return OP_NUMERIC_VALUE;
}
/* Check for a variable */
if (isalpha (*CStringp) || *CStringp == '$')
{
char *p, q;
if (*CStringp == '$')
CStringp++;
p = CStringp;
if (NumberOfVariables == MAX_VARIABLES)
{
ShellErrorMessage ("too many identifiers");
ExpansionErrorDetected = TRUE;
return OP_END_OF_INPUT;
}
RecogniseUnaryOperator = FALSE;
while (isalpha (*++CStringp))
continue;
/* Save the variable name */
q = *CStringp;
*CStringp = '\0';
ListOfVariableNames[yylval = NumberOfVariables++] =
StringCopy (p);
*CStringp = q;
return OP_VARIABLE;
}
return OP_END_OF_INPUT;
}
}
}
/*
* Stick variable on the stack
*/
static void near PushOnToStack (long val, int lval)
{
if (StackPointer == STACK_SIZE - 1)
{
ShellErrorMessage ("stack overflow");
ExpansionErrorDetected = TRUE;
}
else
StackPointer++;
stack[StackPointer].val = val;
stack[StackPointer].lval = lval;
}
/*
* Get a variable value
*/
static long near SetVariableValue (int s, long v)
{
if (s == -1 || s >= NumberOfVariables)
{
ExpansionErrorDetected = TRUE;
ShellErrorMessage ("lvalue required");
return 0;
}
if (JustParsing)
return v;
SetVariableFromNumeric (ListOfVariableNames[s], v);
return v;
}
/*
* Check for Division by zero
*/
static bool near CheckNotZero (long a)
{
if (a)
return TRUE;
ShellErrorMessage ("division by zero");
ExpansionErrorDetected = TRUE;
return FALSE;
}
/*
* Process operator
*/
static void near ProcessOperator (int what)
{
long a, b, c;
int lv;
if (StackPointer < 0)
{
ShellErrorMessage ("bad math expression - stack empty");
ExpansionErrorDetected = TRUE;
return;
}
switch (what)
{
case OP_NOT:
stack[StackPointer].val = !stack[StackPointer].val;
stack[StackPointer].lval= -1;
break;
case OP_COMPLEMENT:
stack[StackPointer].val = ~stack[StackPointer].val;
stack[StackPointer].lval= -1;
break;
case OP_POST_PLUS:
SetVariableValue (stack[StackPointer].lval,
stack[StackPointer].val + 1);
break;
case OP_POST_MINUS:
SetVariableValue (stack[StackPointer].lval,
stack[StackPointer].val - 1);
break;
case OP_UNARY_PLUS:
stack[StackPointer].lval= -1;
break;
case OP_UNARY_MINUS:
stack[StackPointer].val = -stack[StackPointer].val;
stack[StackPointer].lval= -1;
break;
case OP_BINARY_AND_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a & b);
break;
case OP_BINARY_XOR_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a ^ b);
break;
case OP_BINARY_OR_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a | b);
break;
case OP_MULTIPLY:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a * b);
break;
case OP_DIVIDE:
POP_2_VALUES ();
if (CheckNotZero (b))
PUSH_VALUE_ON_STACK (a / b);
break;
case OP_MODULUS:
POP_2_VALUES ();
if (CheckNotZero (b))
PUSH_VALUE_ON_STACK (a % b);
break;
case OP_PLUS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a + b);
break;
case OP_MINUS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a - b);
break;
case OP_SHIFT_LEFT:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a << b);
break;
case OP_SHIFT_RIGHT:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a >> b);
break;
case OP_LESS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a < b);
break;
case OP_LESS_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a <= b);
break;
case OP_GREATER:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a > b);
break;
case OP_GREATER_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a >= b);
break;
case OP_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a == b);
break;
case OP_NOT_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a != b);
break;
case OP_LOGICAL_AND_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a && b);
break;
case OP_LOGICAL_OR_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (a || b);
break;
case OP_LOGICAL_XOR_EQUALS:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK ((a && !b) || (!a && b));
break;
case OP_QUESTION_MARK:
c = stack[StackPointer--].val;
POP_2_VALUES ();
PUSH_VALUE_ON_STACK ((a) ? b : c);
break;
case OP_COLON:
break;
case OP_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (b);
break;
case OP_PLUS_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a + b);
break;
case OP_MINUS_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a - b);
break;
case OP_MULTIPLY_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a * b);
break;
case OP_DIVIDE_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
if (CheckNotZero (b))
SET_VALUE_ON_STACK (a / b);
break;
case OP_MODULUS_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
if (CheckNotZero (b))
SET_VALUE_ON_STACK (a % b);
break;
case OP_BINARY_AND_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a & b);
break;
case OP_BINARY_XOR_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a ^ b);
break;
case OP_BINARY_OR_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a | b);
break;
case OP_SHIFT_LEFT_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a << b);
break;
case OP_SHIFT_RIGHT_EQUAL:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a >> b);
break;
case OP_LOGICAL_AND_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a && b);
break;
case OP_LOGICAL_OR_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK (a || b);
break;
case OP_LOGICAL_XOR_SET:
POP_2_VALUES ();
lv = stack[StackPointer + 1].lval;
SET_VALUE_ON_STACK ((a && !b) || (!a && b));
break;
case OP_COMMA:
POP_2_VALUES ();
PUSH_VALUE_ON_STACK (b);
break;
case OP_PRE_PLUS:
stack[StackPointer].val =
SetVariableValue (stack[StackPointer].lval,
stack[StackPointer].val + 1);
break;
case OP_PRE_MINUS:
stack[StackPointer].val =
SetVariableValue (stack[StackPointer].lval,
stack[StackPointer].val - 1);
break;
default:
ShellErrorMessage ("out of integers");
ExpansionErrorDetected = TRUE;
return;
}
}
/*
* Handle binary operators
*/
static void near ProcessBinaryOperator (int tk)
{
switch (tk)
{
case OP_LOGICAL_AND_EQUALS:
case OP_LOGICAL_AND_SET:
if (!stack[StackPointer].val)
JustParsing++;
break;
case OP_LOGICAL_OR_EQUALS:
case OP_LOGICAL_OR_SET:
if (stack[StackPointer].val)
JustParsing++;
break;
}
}
/*
* Common processing
*/
long EvaluateMathsExpression (char *s)
{
int i;
for (i = 0; i != MAX_VARIABLES; i++)
ListOfVariableNames[i] = (char *)NULL;
LastNumberBase = -1; /* Reset base */
NumberOfVariables = 0;
CStringp = s;
StackPointer = -1;
RecogniseUnaryOperator = TRUE;
ParseMathsExpression (MAX_PRECEDENCE);
if (StackPointer)
{
ShellErrorMessage ("bad math expression - unbalanced stack");
ExpansionErrorDetected = TRUE;
}
if (*CStringp)
{
ShellErrorMessage ("bad math expression - illegal character: %c",
*CStringp);
ExpansionErrorDetected = TRUE;
}
for (i = 0; i != NumberOfVariables; i++)
ReleaseMemoryCell ((void *)ListOfVariableNames[i]);
return stack[0].val;
}
/*
* operator-precedence parse the string and execute
*/
static void near ParseMathsExpression (int pc)
{
LastToken = MathsLexicalAnalyser ();
while (Operators[LastToken].Precedences <= pc)
{
if (LastToken == OP_NUMERIC_VALUE)
PushOnToStack (yyval, -1);
else if (LastToken == OP_VARIABLE)
PushOnToStack (GetVariableAsNumeric (ListOfVariableNames[yylval]),
yylval);
else if (LastToken == OP_OPEN_PAR)
{
ParseMathsExpression (MAX_PRECEDENCE);
if (LastToken != OP_CLOSE_PAR)
{
ShellErrorMessage ("unmatched ()'s");
return;
}
}
else if (LastToken == OP_QUESTION_MARK)
{
long q = stack[StackPointer].val;
if (!q)
JustParsing++;
ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences - 1);
if (!q)
JustParsing--;
else
JustParsing++;
ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences);
if (q)
JustParsing--;
ProcessOperator (OP_QUESTION_MARK);
continue;
}
else
{
int otok = LastToken;
int onoeval = JustParsing;
if (Operators[otok].Type == BOOL_A)
ProcessBinaryOperator (otok);
ParseMathsExpression (Operators[otok].Precedences -
(Operators[otok].Type != RIGHT_LEFT_A));
JustParsing = onoeval;
ProcessOperator (otok);
continue;
}
LastToken = MathsLexicalAnalyser ();
}
}
/*
* Decide on 'op=', 'opop' or 'op'
*/
static int near DecideDoubleOperator (char op, int dequal, int equal,
int twice, int single)
{
RecogniseUnaryOperator = TRUE;
if (*CStringp == op)
{
if (*(++CStringp) == '=')
{
CStringp++;
return dequal;
}
return twice;
}
else if (*CStringp == '=')
{
CStringp++;
return equal;
}
return single;
}
/*
* Decide on single operator 'op' or 'op='
*/
static int near DecideSingleOperator (int equal, int single)
{
RecogniseUnaryOperator = TRUE;
if (*CStringp != '=')
return single;
CStringp++;
return equal;
}
/*
* Handle +=, ++, + or -=, --, -
*/
static int near DecideSignOperator (char sign, int pre_op, int post_op,
int equals, int unary_op, int op)
{
if ((*CStringp == sign) && (RecogniseUnaryOperator || !isalnum (*CStringp)))
{
CStringp++;
return RecogniseUnaryOperator ? pre_op : post_op;
}
if (*CStringp == '=')
{
RecogniseUnaryOperator = TRUE;
CStringp++;
return equals;
}
return RecogniseUnaryOperator ? unary_op : op;
}
/*
* Validate maths expression without the error message generated a
* command. This forces the processing to drop down the stack rather than
* doing a deep-exit on error.
*/
bool ValidMathsExpression (char *string, long *value)
{
int *Save_ERP = e.ErrorReturnPoint;
bool Save_EED = ExpansionErrorDetected;
bool Result;
/* save the environment */
e.ErrorReturnPoint = NULL;
ExpansionErrorDetected = FALSE;
/* Validate the number */
*value = EvaluateMathsExpression (string);
Result = ExpansionErrorDetected;
/* Restore environment */
e.ErrorReturnPoint = Save_ERP;
ExpansionErrorDetected = Save_EED;
return Result;
}